#ifndef ___fat32_transacciones_funciones_auxiliares_1

#define ___fat32_transacciones_funciones_auxiliares_1 1

#include <stdlib.h>
#include "f32_tfa2.c"
#include "f32_oper.c"
#include "f32_rec.c"
#include "f32_tcon.c"
#include "f32_rbda.c"

void fat32_insertar_transaccion_en_cola_pendientes(fat32_transaccion_no_ejecutada);
fat32_transaccion_no_ejecutada fat32_tomar_primera_transaccion_pendiente(void);
void fat32_crear_nueva_transaccion_en_proceso (fat32_transaccion_no_ejecutada);
void fat32_procesar_transaccion (fat32_transaccion *);
int fat32_saltear_transacciones_bloqueadas(void);
struct fat32_nodo_trans * fat32_buscar_nodo_transaccion(unsigned int);
struct fat32_nodo_trans * fat32_buscar_nodo_transaccion_anterior(struct fat32_nodo_trans *);
void fat32_limpiar_datos_transaccion(unsigned int);

void fat32_insertar_transaccion_en_cola_pendientes (fat32_transaccion_no_ejecutada nuevaTransaccion) {
  struct fat32_nodo_trans_pend * nodo = malloc(sizeof(fat32_nodo_trans_pend));
  nodo -> siguiente = NULL;
  nodo -> transaccionPendiente = nuevaTransaccion;
  if (fat32_transacciones.ultimaPendiente) {
    (fat32_transacciones.ultimaPendiente) -> siguiente = nodo;
    fat32_transacciones.ultimaPendiente = nodo;
  } else
    fat32_transacciones.ultimaPendiente = fat32_transacciones.primeraPendiente = nodo;
}

fat32_transaccion_no_ejecutada fat32_tomar_primera_transaccion_pendiente (void) {
  struct fat32_nodo_trans_pend * nodo = fat32_transacciones.primeraPendiente;
  if (nodo) {
    fat32_transaccion_no_ejecutada transaccion = nodo -> transaccionPendiente;
    fat32_transacciones.primeraPendiente = nodo -> siguiente;
    if (!fat32_transacciones.primeraPendiente) fat32_transacciones.ultimaPendiente = NULL;
    free(nodo);
    return transaccion;
  }
}

void fat32_crear_nueva_transaccion_en_proceso (fat32_transaccion_no_ejecutada transaccion) {
  unsigned int nuevoID = ++ fat32_siguiente_numero_transaccion;
  void * datosInternos = NULL;
  int (* nuevoHandler) (unsigned int, int, unsigned char, void *, void **) = NULL;
  int estado = (*(transaccion.handler)) (nuevoID, transaccion.datos, &datosInternos, &nuevoHandler);
  free(transaccion.datos);
  if (!estado) {
    fat32_limpiar_datos_transaccion(nuevoID);
    return;
  }
  fat32_transaccion trns;
  trns.ID = nuevoID;
  trns.estado = estado;
  trns.handler = nuevoHandler;
  trns.datos = datosInternos;
  trns.tieneOperacion = 0;
  struct fat32_nodo_trans * nodo = malloc(sizeof(struct fat32_nodo_trans));
  nodo -> transaccion = trns;
  if (fat32_transacciones.actualEnProceso) {
    struct fat32_nodo_trans * nodoFinal = fat32_buscar_nodo_transaccion_anterior(fat32_transacciones.actualEnProceso);
    nodoFinal -> siguiente = nodo;
    nodo -> siguiente = fat32_transacciones.actualEnProceso;
  } else {
    nodo -> siguiente = nodo;
    fat32_transacciones.actualEnProceso = nodo;
  }
}

void fat32_procesar_transaccion (fat32_transaccion * transaccion) {
  unsigned char resultado = 0;
  int estado;
  if ((transaccion -> tieneOperacion) && !((transaccion -> operacion).estado)) {
    resultado = fat32_procesar_operacion(transaccion -> ID, transaccion -> operacion
    (transaccion -> operacion).estado = resultado;
  }
  if (resultado) {
    void * datos = (transaccion -> operacion).datosSalida;
    if (fat32_transaccion_esta_bloqueada(transaccion -> ID)) return;
    estado = (*(transaccion -> handler)) (transaccion -> ID, transaccion -> estado, resultado, datos, &(transaccion -> datos));
  } else {
    if (fat32_transaccion_esta_bloqueada(transaccion -> ID)) return;
    estado = (*(transaccion -> handler)) (transaccion -> ID, transaccion -> estado, 0, NULL, &(transaccion -> datos));
  }
  transaccion -> estado = estado;
  if (!estado) fat32_terminar_transaccion(transaccion -> ID);
}

int fat32_saltear_transacciones_bloqueadas (void) {
  struct fat32_nodo_trans * transActual = fat32_transacciones.actualEnProceso;
  if (!fat32_transaccion_esta_bloqueada((transActual -> transaccion).ID)) return 0;
  fat32_transacciones.actualEnProceso = fat32_transacciones.actualEnProceso -> siguiente;
  while (fat32_transacciones.actualEnProceso != transActual) {
    if (!fat32_transaccion_esta_bloqueada((fat32_transacciones.actualEnProceso -> transaccion).ID)) return 0;
    fat32_transacciones.actualEnProceso = fat32_transacciones.actualEnProceso -> siguiente;
  }
  return 1;
}

struct fat32_nodo_trans * fat32_buscar_nodo_transaccion (unsigned int transaccion) {
  if (!fat32_transacciones.actualEnProceso) return NULL;
  if ((fat32_transacciones.actualEnProceso -> transaccion).ID == transaccion)
    return fat32_transacciones.actualEnProceso;
  struct fat32_nodo_trans * nodoActual;
  for (nodoActual = fat32_transacciones.actualEnProceso -> siguiente; nodoActual != fat32_transacciones.actualEnProceso;
       nodoActual = nodoActual -> siguiente)
    if ((nodoActual -> transaccion).ID == transaccion)
      return nodoActual;
  return NULL;
}

struct fat32_nodo_trans * fat32_buscar_nodo_transaccion_anterior (struct fat32_nodo_trans * transaccion) {
  if (!fat32_transacciones.actualEnProceso) return NULL;
  if ((fat32_transacciones.actualEnProceso -> siguiente) == transaccion)
    return fat32_transacciones.actualEnProceso;
  struct fat32_nodo_trans nodoActual;
  for (nodoActual = fat32_transacciones.actualEnProceso -> siguiente; nodoActual != fat32_transacciones.actualEnProceso;
       nodoActual = nodoActual -> siguiente)
    if ((nodoActual -> siguiente) == transaccion)
      return nodoActual;
  return NULL;
}

void fat32_limpiar_datos_transaccion (unsigned int transaccion) {
  unsigned int posicion;
  for (posicion = 0; posicion < fat32_recursos.cantConexiones; posicion ++)
    if (fat32_recursos.conexiones[posicion].transaccion == transaccion)
      fat32_liberar_conexion_de_transaccion(transaccion);
  for (posicion = 0; posicion < fat32_recursos.cantArchivos; posicion ++)
    if (fat32_recursos.archivos[posicion].transaccion == transaccion)
      fat32_liberar_acceso_sobre_elemento(transaccion, fat32_recursos.archivos[posicion].descriptor);
}

#endif